package com.erp.erp_servers.Email.Impl;

import com.erp.erp_entitys.Email.*;
import com.erp.erp_servers.CustomerContact.ICustomerContactService;
import com.erp.erp_servers.Email.EmailService;
import com.erp.erp_servers.Ftp.IFtpService;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.*;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;

class ServiceSendEmail {

    /**
     * 后加的防止题目过长并且进行全局定义
     */
    static {
        System.setProperty("mail.mime.splitlongparameters", "false");
        System.setProperty("mail.mime.charset", "UTF-8");
    }

    /*
     //发件人地址
     public static String senderAddress = "xxx@163.com";
     //收件人地址
     public static String recipientAddress = "xxx@qq.com";
     //发件人账户名
     public static String senderAccount = "xxx";
     //发件人账户密码
     public static String senderPassword = "xxx";
     */
    public static Session smtptest(email_smtp smtp) throws MessagingException {
        //1、连接邮件服务器的参数配置
        Properties props = new Properties();
        //设置用户的认证方式
        props.setProperty("mail.smtp.port", smtp.getSmtp_port());
        props.setProperty("mail.smtp.auth", "true");
        //设置传输协议
        props.setProperty("mail.transport.protocol","smtp");
        //设置发件人的SMTP服务器地址
        props.setProperty("mail.smtp.host", smtp.getSmtp_server());
        //2、创建定义整个应用程序所需的环境信息的 Session 对象
        Session session = Session.getInstance(props);
        //4、根据session对象获取邮件传输对象Transport
        props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); // 使用JSSE的SSL
        props.put("mail.smtp.socketFactory.fallback", "false"); // 只处理SSL的连接,对于非SSL的连接不做处理

        return session;
    }

    public static void sendEmail(email_smtp smtp, email_message message, EmailService emailService, email_deploy deploy, HashMap<String, String> basePices, IFtpService ftp, String baseContext, ICustomerContactService customerContactService) throws Exception {
        //1、连接邮件服务器的参数配置
        Properties props = new Properties();
        //设置用户smtp端口号
        props.setProperty("mail.smtp.port", smtp.getSmtp_port());
        props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); // 使用JSSE的SSL
        props.put("mail.smtp.socketFactory.fallback", "false"); // 只处理SSL的连接,对于非SSL的连接不做处理
        //设置用户的认证方式
        props.setProperty("mail.smtp.auth", "true");
        //设置传输协议
        props.setProperty("mail.transport.protocol","smtp");
        //设置发件人的SMTP服务器地址
        props.setProperty("mail.smtp.host", smtp.getSmtp_server());
        //2、创建定义整个应用程序所需的环境信息的 Session 对象
        Session session = Session.getInstance(props);
        //设置调试信息在控制台打印出来
        session.setDebug(true);
        //3、创建邮件的实例对象
        MimeMessage mim = getMimeMessage(session, message, smtp,deploy);
        //这里来控制群发还是单发
        if (message.getIsmore()==1) {//单发
            //设置邮件主题
            String subject = MimeUtility.encodeWord(message.getSubject(),  message.getCharset(), "Q");
            mim.setSubject(subject);
            //设置邮件发送对象
            /* 设置收件人地址（可以增加多个收件人、抄送、密送），即下面这一行代码书写多行
         MimeMessage.RecipientType.TO;//发送
         MimeMessage.RecipientType.CC;//抄送
         MimeMessage.RecipientType.BCC;//密送
         */
            int con=0;//收件人控制器
            Iterator<Map.Entry<String, String>> iterator = message.getSendAddres().entrySet().iterator();
            String sendAdd="";
            String sendName="";
            List<String> returnCustomer=new ArrayList<>();
            while(iterator.hasNext()){
                Map.Entry<String, String> next = iterator.next();
                if(con==0){
                    mim.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress(next.getValue()));
                    con++;
                    sendAdd+=next.getValue()+";";
                    returnCustomer.add(next.getValue());
                    sendName+=next.getKey()+";";
                }else{
                    mim.addRecipient(MimeMessage.RecipientType.TO, new InternetAddress(next.getValue()));
                    sendAdd+=next.getValue()+";";
                    returnCustomer.add(next.getValue());
                    sendName+=next.getKey()+";";
                }
            }
            String copyAdd="";
            Address[] copAdd=new Address[message.getCopyAddress().size()];
            if (message.getCopyAddress().size()>0) {
                int i=0;
                for (String cop : message.getCopyAddress()) {
                    if(cop!=""){
//                        mim.setRecipient(MimeMessage.RecipientType.CC, new InternetAddress(cop));
                        copAdd[i]=new InternetAddress(cop);
                        copyAdd+=cop+";";
                        returnCustomer.add(cop);
                    }
                    i++;
                }
            }
            mim.setRecipients(MimeMessage.RecipientType.CC, copAdd);
            String DarkAdd="";
            Address[] DarkAdds=new Address[message.getDarkAddress().size()];
            if (message.getDarkAddress().size()>0) {
                int i=0;
                for (String dar : message.getDarkAddress()) {
                    if(dar!=""){
//                        mim.setRecipient(MimeMessage.RecipientType.BCC, new InternetAddress(dar));
                        DarkAdds[i]=new InternetAddress(dar);
                        DarkAdd+=dar+";";
                        returnCustomer.add(dar);
                    }
                    i++;
                }
            }
            mim.setRecipients(MimeMessage.RecipientType.BCC, DarkAdds);
            mim.setFrom(smtp.getEmail_adress());
            Message msg = (Message) mim;
            //4、根据session对象获取邮件传输对象Transport
            Transport transport = session.getTransport();
            //设置发件人的账户名和密码
            transport.connect(smtp.getEmail_name(), smtp.getEmail_password());
            //发送邮件，并发送到所有收件人地址，message.getAllRecipients() 获取到的是在创建邮件对象时添加的所有收件人, 抄送人, 密送人
            transport.sendMessage(msg, msg.getAllRecipients());
            //5、关闭邮件连接
            transport.close();
            //存入数据库
        } else {//群发  需要考试时间因素
            List<String> subjects = message.getSubjects();
            String subj="";
            String sendN="";
            String sendA="";
            for(String s:subjects){
                subj+=s+";";
            }
            int index = 0;//用来控制主题的循环
            Map<String, String> sendAddress = message.getSendAddress();
            Set<Map.Entry<String, String>> entries = sendAddress.entrySet();
            Iterator<Map.Entry<String, String>> iterator = entries.iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, String> next = iterator.next();//发送地址  key=用户名 value=地址
                mim.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress(next.getValue()));
                List<String> returnCustomer=new ArrayList<>();
                returnCustomer.add(next.getValue());
                List<String> strings = ServerciEmailUnit.returnCustomers(emailService, returnCustomer);
                try {
                    if(strings.size()>0){
                        customerContactService.updateByEmail(strings);}
                }catch (Exception e){

                }
                String subject = MimeUtility.encodeWord(subjects.get(index),  message.getCharset(), "Q");
                mim.setSubject(subject);
                index++;
                //控制主题循环
                if (index == subjects.size()) {
                    index = 0;
                }
                Message msg = (Message) mim;
                //4、根据session对象获取邮件传输对象Transport
                Transport transport = session.getTransport();
                //设置发件人的账户名和密码
                transport.connect(smtp.getEmail_name(), smtp.getEmail_password());
                //发送邮件，并发送到所有收件人地址，message.getAllRecipients() 获取到的是在创建邮件对象时添加的所有收件人, 抄送人, 密送人
                transport.sendMessage(msg, msg.getAllRecipients());
                //5、关闭邮件连接
                transport.close();
                //群发间隔时间
                Integer momStart = deploy.getMomStart();
                if(momStart==null){
                    momStart=1;
                }
                Integer momEnd = deploy.getMomEnd();
                if(momEnd==null){
                    momEnd=3;
                }
                Random random = new Random();
                int s = random.nextInt(momEnd)%(message.getMomEnd()-momStart+1) + message.getMomStart();
                sendN+=next.getKey()+";";
                sendA+=next.getValue()+";";
                Thread.sleep(s);
            }

            int picNum=0;
            int aduNum=0;
            if(message.getPictures()!=null){
                picNum=message.getPictures().size();
            }
            if(message.getAduncts()!=null){
                aduNum=message.getAduncts().size();
            }
            email_email email=new email_email(-1,smtp.getSmtp_server(),-1,-1,-1,-1,1,subj,smtp.getSmtp_name(),smtp.getEmail_adress(),sendN,sendA,null,null,null,0,smtp.getEmail_code(), ServerciEmailUnit.getNowSqlDate(), ServerciEmailUnit.getNowSqlDate(), ServerciEmailUnit.getNowSqlDate(),message.getCharset(),1,smtp.getSmtp_id(),0,picNum,aduNum,0,null,0);
            emailService.addEmail_email(email);
            int id = email.getEmail_id();
            //数据库保存正文
            int size=0;
            if(message.getContenct()!=null&&message.getContenct()!=""){
                email_adjunct context=new email_adjunct();
                context.setEmail_id(id);
                context.setIsText(1);
                context.setTextAddress(baseContext);
                size+=(baseContext.length()/1024);
                emailService.insertEmail_adjunct(context);
            }
            //数据库保存图片
            if(message.getPictures()!=null){
                Iterator<Map.Entry<String, String>> iterator1 = basePices.entrySet().iterator();
                while(iterator1.hasNext()){
                    Map.Entry<String, String> next = iterator1.next();
                    String key = next.getKey();//图片名
                    String value = next.getValue();//图片地址
                    email_adjunct pic=new email_adjunct();
                    pic.setEmail_id(id);
                    pic.setIsHasAtta(1);
                    pic.setOldHasAtta(key);
                    pic.setCidHas(value);
                    pic.setNewHasAtta(value);
                    size+=new File(value).length();
                    emailService.insertEmail_adjunct(pic);
                }
            }
            //数据库保存附件
            String pathName = "/email/" + smtp.getEmail_adress() + "/" + id + "/"+ServerciEmailUnit.getRandomFileName();
            if(message.getAduncts()!=null){
                HashMap<String, String> aduncts = (HashMap<String, String>)message.getAduncts();
                Iterator<Map.Entry<String, String>> iterator1 = aduncts.entrySet().iterator();
                while(iterator1.hasNext()){
                    Map.Entry<String, String> next = iterator1.next();
                    String key = next.getKey();//附件名
                    String value = next.getValue();//附件地址
                    FileInputStream inputStream=new FileInputStream(new File(value));
                    String upPath = ftp.uploadEmailAdjunct(pathName,ServerciEmailUnit.getRandomFileName(), inputStream);
                    String[] split = upPath.split("&filename");
                    upPath=split[0]+"/"+"&filename"+split[1];
                    email_adjunct ad=new email_adjunct();
                    ad.setEmail_id(id);
                    ad.setIsAdunct(1);
                    ad.setAdjunctName(key);
                    ad.setAdjunctAddress(upPath);
                    size+=new File(value).length();
                    emailService.insertEmail_adjunct(ad);
                }
            }
            if(size==0){
                size=1;
            }
            emailService.setEmailSize(id,size);
            /*
            String adjName = null;
            if(message.getAduncts()!=null){
                Iterator<Map.Entry<String, String>> iterator1 = message.getAduncts().entrySet().iterator();
                while(iterator1.hasNext()){
                    Map.Entry<String, String> next = iterator1.next();
                    adjName+=next.getKey()+";";
                }
            }
            email_mass mass=new email_mass(subj, ServerciEmailUnit.getNowSqlDate(),sendN,sendA,message.getContenct(),adjName);
            emailService.insertEmail_mass(mass);
        }*/
        }}
    /**
     * 获得创建一封邮件的实例对象
     *
     * @param session
     * @return
     * @throws MessagingException
     * @throws AddressException
     */
    public static MimeMessage getMimeMessage(Session session, email_message message, email_smtp smtp, email_deploy deploy) throws Exception {
        //1.创建一封邮件的实例对象
        MimeMessage msg = new MimeMessage(session);
        //2.设置发件人地址
        msg.setFrom(new InternetAddress(smtp.getEmail_name()));

        if (message.getPictures().size()==0 && message.getAduncts().size()==0) {
            msg.setContent(message.getContenct(), "text/html;charset=UTF-8");
        } else if (message.getPictures().size()>0 && message.getAduncts().size()==0) {
            MimeMultipart mm_text_image = new MimeMultipart("related");
            msg.setContent(mm_text_image);
            // 6. 创建文本"节点"
            MimeBodyPart text = new MimeBodyPart();
            mm_text_image.addBodyPart(text);
            // 这里添加图片的方式是将整个图片包含到邮件内容中, 实际上也可以以 http 链接的形式添加网络图片
            text.setContent(message.getContenct(), "text/html;charset=UTF-8");
            // 7. （文本+图片）设置 文本 和 图片"节点"的关系（将 文本 和 图片"节点"合成一个混合"节点"）
            List<MimeBodyPart> parts = keepPicture(message.getPictures());
            for (MimeBodyPart m : parts) {
                mm_text_image.addBodyPart(m);
            }
            msg.saveChanges();
        } else if (message.getPictures().size()==0 && message.getAduncts().size()>0) {
            //创建附件“节点”
            MimeMultipart mm = new MimeMultipart("mixed");
            msg.setContent(mm);
            // 6. 创建文本"节点"
            MimeBodyPart text = new MimeBodyPart();
            mm.addBodyPart(text);
            // 这里添加图片的方式是将整个图片包含到邮件内容中, 实际上也可以以 http 链接的形式添加网络图片
            text.setContent(message.getContenct(), "text/html;charset=UTF-8");
            List<MimeBodyPart> parts = keepAdjunct(message.getAduncts());
            for (MimeBodyPart m : parts) {
                mm.addBodyPart(m);     // 如果有多个附件，可以创建多个多次添加
            }
            msg.saveChanges();
        } else if (message.getPictures().size()>0&& message.getAduncts().size()>0) {
            // 1. 总节点，子节点为正文+附件
            MimeMultipart mm = new MimeMultipart("mixed");
            //2.总结点加入邮件体
            msg.setContent(mm);
            //3.创建正文节点
            MimeBodyPart text_image = new MimeBodyPart();
            //4.创建附件节点
            List<MimeBodyPart> adjs = keepAdjunct(message.getAduncts());
            //5.总节点加入正文节点
            mm.addBodyPart(text_image);
            //6.总结点加入附件节点
            for (MimeBodyPart adj : adjs) {
                mm.addBodyPart(adj);
            }
            // 7. 正文混合节点
            MimeMultipart mm_text_image = new MimeMultipart("related");
            //8.正文混合接地那加入正文节点
            text_image.setContent(mm_text_image);
            // 9. 创建文本"节点"
            MimeBodyPart text = new MimeBodyPart();
            //10.正文混合节点加入文本节点
            mm_text_image.addBodyPart(text);
            // 这里添加图片的方式是将整个图片包含到邮件内容中, 实际上也可以以 http 链接的形式添加网络图片
            text.setContent(message.getContenct(), "text/html;charset=UTF-8");
            //11.加入正文图片节点
            List<MimeBodyPart> picts = keepPicture(message.getPictures());
            for (MimeBodyPart pic : picts) {
                mm_text_image.addBodyPart(pic);
            }
            msg.saveChanges();
        }
        //设置邮件的发送时间,默认立即发送
        Date date=new Date();
        msg.setSentDate(date);
        return msg;
    }
    //正文图片处理
    public static List<MimeBodyPart> keepPicture(Map<String, String> pictures) throws MessagingException, UnsupportedEncodingException {
        List<MimeBodyPart> pics = new ArrayList<>();
        Set<Map.Entry<String, String>> entrySet = pictures.entrySet();
        Iterator<Map.Entry<String, String>> iterator = entrySet.iterator();
        String fen = System.getProperty("file.separator");
        //因为绝对地址可能重复，因此需要对绝对地址进行修改
        ArrayList<String> arr=new ArrayList<>();
        while (iterator.hasNext()) {
            Map.Entry<String, String> next = iterator.next();
            String cid = next.getKey();//cid
            String address = next.getValue();//绝对地址
            if(arr.contains(address)==false){
                //不重复
                arr.add(address);
            }else{
                //重复
                File tempFile =new File( address.trim());
                String fileName = tempFile.getName();
                String path = address.split(fileName)[0];
                String add=path+ServerciEmailUnit.getRandomFileName()+".jpg";
                try {
                    copyFileUsingFileStreams(new File(address),new File(add));
                }catch (Exception e){
                    System.out.println(e);
                }
                arr.add(add);
                address=add;
            }
            // 5. 创建图片"节点"
            MimeBodyPart image = new MimeBodyPart();
            // 读取本地文件
            File file=new File(address);
            DataHandler dh = new DataHandler(new FileDataSource(file));
            // 将图片数据添加到"节点"
            image.setDataHandler(dh);
            // 为"节点"设置一个唯一编号（在文本"节点"将引用该ID）
            cid=cid.split("cid:")[1];
            image.setContentID("<"+cid+">");
            image.setFileName(MimeUtility.encodeText(file.getName()));
            pics.add(image);
        }
        return pics;
    }

    private static void copyFileUsingFileStreams(File source, File dest)
            throws IOException {
        InputStream input = null;
        OutputStream output = null;
        try {
            input = new FileInputStream(source);
            output = new FileOutputStream(dest);
            byte[] buf = new byte[1024];
            int bytesRead;
            while ((bytesRead = input.read(buf)) != -1) {
                output.write(buf, 0, bytesRead);
            }
        } finally {
            input.close();
            output.close();
        }
    }

    //附件处理
    public static List<MimeBodyPart> keepAdjunct(Map<String, String> aduncts) throws MessagingException, UnsupportedEncodingException {
        List<MimeBodyPart> adjus = new ArrayList<>();
        Set<Map.Entry<String, String>> entries = aduncts.entrySet();
        Iterator<Map.Entry<String, String>> iterator = entries.iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, String> next = iterator.next();
            String name = next.getKey();
            String address = next.getValue();
            // 9. 创建附件"节点"
            MimeBodyPart attachment = new MimeBodyPart();
            // 读取本地文件
            File file=new File(next.getValue());
            DataHandler dh2 = new DataHandler(new FileDataSource(file));
            // 将附件数据添加到"节点"
            attachment.setDataHandler(dh2);
            // 设置附件的文件名（需要编码）
            attachment.setFileName(MimeUtility.encodeText(name, "UTF-8", "B"));
            adjus.add(attachment);
        }
        return adjus;
    }

    //保存一封邮件到服务器：一般用作保存草稿及审批方面    实现思路，将邮件拆分成email_email  和adjuct
    public static void keepEmail(email_message message){
        int email_class=-1;
        if(message.getIsmore()==1){
            email_class=3;
        }else{
            email_class=4;
        }
        String subj=null;//主题
        String sendA=null;//发送地址
        String copyA=null;//抄送地址
        String darkA=null;//暗送地址
        if (email_class==3){//单发
            subj=message.getSubject();
            Iterator<Map.Entry<String, String>> iterator = message.getSendAddres().entrySet().iterator();
            while (iterator.hasNext()){
                Map.Entry<String, String> next = iterator.next();
                sendA+=next.getValue()+";";
            }
            for (String cop:message.getCopyAddress()){
                copyA+=cop+";";
            }
            for(String dark:message.getDarkAddress()){
                darkA+=dark+";";
            }
        }else{
            for(String su:message.getSubjects()){
                subj+=su+";";
            }
            Iterator<Map.Entry<String, String>> iterator = message.getSendAddress().entrySet().iterator();
            while (iterator.hasNext()){
                Map.Entry<String, String> next = iterator.next();
                sendA+=next.getValue()+";";
            }
        }
        int picNum=0;
        int adjNum=0;
        if(message.getPictures()!=null){
            picNum=message.getPictures().size();
        }
        if(message.getAduncts()!=null){
            adjNum=message.getAduncts().size();
        }
        email_email email=new email_email(-1,null,-1,-1,-1,-1,email_class,subj,null,null,null,sendA,null,copyA,darkA,0,"ceil",null,null,null,message.getCharset(),0,-1,-1,picNum,adjNum,1,null,0);
        //邮件插入数据库，返回id
        int emailID=0;
        email_adjunct adjuct1=new email_adjunct(emailID,0,0,1,null,message.getContenct(),null,null,null,null,0);//正文
        List<email_adjunct> adjuct2=new ArrayList<>();//正文图片 图片要保存到本地，并且返回路径
        Map<String, String> pictures = message.getPictures();//key为cid value为ftp路径
        Iterator<Map.Entry<String, String>> iterator = pictures.entrySet().iterator();
        while (iterator.hasNext()){
            Map.Entry<String, String> next = iterator.next();
            adjuct2.add(new email_adjunct(emailID,1,0,0,next.getKey(),null,null,next.getValue(),null,null,0));
        }
        Map<String, String> aduncts = message.getAduncts();//key为附件名，value为ftp路径
        List<email_adjunct> adjuct3=new ArrayList<>();//附件
        Iterator<Map.Entry<String, String>> iterator1 = aduncts.entrySet().iterator();
        while(iterator1.hasNext()){
            Map.Entry<String, String> next = iterator1.next();
            adjuct3.add(new email_adjunct(emailID,0,1,0,null,null,null,null,next.getKey(),next.getValue(),0));
        }
        //数据库保存数据
    }
}